package com.qf.commons.web.apiversion;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;

import javax.servlet.http.HttpServletRequest;

/**
 * description: 多版本接口的请求条件对象
 * author: Ken
 * 公众号：Java架构栈
 */
public class ApiVersionRequestCondition implements RequestCondition<ApiVersionRequestCondition> {

    //表示当前条件的版本号
    private double apiVersion = 1.0;

    public double getApiVersion() {
        return apiVersion;
    }

    public ApiVersionRequestCondition(double apiVersion){
        this.apiVersion = apiVersion;
    }

    private static final String VERSION_NAME = "api-version";

    /**
     * 时机：当客户端发送请求时，触发该方法
     *
     * 当Class上的条件和Method上的条件同时存在时，如何结合？
     * @param method
     * @return
     */
    @Override
    public ApiVersionRequestCondition combine(ApiVersionRequestCondition method) {
        //this 代表Controller的请求条件
        //method 代表Controller中某个方法的请求条件
        return method;
    }

    /**
     * 时机：当客户端发送请求时，触发该方法
     *
     * 根据请求，判断当前RequestCondition对象是否符合匹配条件，
     * 如果符合，就返回当前对象本身
     * 如果不符合，就返回null
     *
     * @param request
     * @return
     */
    @Override
    public ApiVersionRequestCondition getMatchingCondition(HttpServletRequest request) {
        //请求的版本号
        double reqVersionDouble = 1.0;

        //获取请求中的版本信息
        String reqVersion = request.getHeader(VERSION_NAME);
        if (StringUtils.isEmpty(reqVersion)) {
            //从参数中获取
            reqVersion = request.getParameter(VERSION_NAME);
        }

        //判断是否从请求中获取到版本号
        if (!StringUtils.isEmpty(reqVersion)) {
            try {
                reqVersionDouble = Math.max(Double.parseDouble(reqVersion), 1.0);
            } catch (Throwable t){
                reqVersionDouble = 1.0;
            }
        }

        //用请求的版本号和当前条件的版本号，进行对比
        //采用<=的比较形式，支持服务端接口的向上兼容，例如：2.0版本的接口，可以支持2.0+的版本的请求
        if (this.getApiVersion() <= reqVersionDouble){
            //当前方法 已经匹配了当前的请求，返回条件本身
            return this;
        }
        //说明没有匹配，则返回null，那么这个条件对应的方法就不符合请求的版本要求
        return null;
    }

    /**
     * 时机：当客户端发送请求时，触发该方法
     *
     * 排序 - 为了选择最优的条件匹配对象
     * @param other
     * @param request
     * @return
     */
    @Override
    public int compareTo(ApiVersionRequestCondition other, HttpServletRequest request) {
        //降序排列，让版本号更大的接口，排在前面
        return Double.compare(other.getApiVersion(), this.getApiVersion());
    }
}
